/*
 * File Name：AudioPlayer.java
 * Copyright：Copyright 2008-2013 CiWong.Inc. All Rights Reserved.
 * Description： AudioPlayer.java
 * Modify By：PLA-ZJLIU
 * Modify Date：2013-12-11
 * Modify Type：Add
 */
package com.ciwong.libs.audio.play;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnSeekCompleteListener;
import android.os.Handler;
import android.os.Looper;

import com.ciwong.libs.utils.CWLog;
import com.ciwong.libs.utils.CWSys;
import com.ciwong.libs.utils.FileUtils;
import com.ciwong.libs.utils.StringUtils;
import com.ciwong.libs.utils.volley.AsyncDownload;
import com.ciwong.libs.utils.volley.AsyncDownload.DownloadTask;
import com.ciwong.mobilelib.utils.BaseSystem;

/**
 * 播放器
 * 
 * @author PLA-ZJLIU
 * @version ciwong v.1.0 2013-12-11
 * @since ciwong v.1.0
 */
public class AudioPlayer
{
    private final static String TAG = "AudioPlayer";

    /**
     * 播放地址错误
     */
    public static final int PLAY_ERROR_MP3 = 0;

    /**
     * 文件不存在
     */
    public static final int PLAY_ERROR_FILE_NOT_EXISTS = 2;

    /**
     * 不支持的播放地址协议，目前只支持http://，file://
     */
    public static final int PLAY_ERROR_NOT_SUPORT_SCHEMA = 3;

    /**
     * 下载音频文件失败
     */
    public static final int PLAY_ERROR_DOWNLOAD = 4;

    /**
     * 音频播放器初始化错误
     */
    public static final int PLAY_ERROR_INIT = 5;

    /**
     * 播放音乐失败
     */
    public static final int PLAY_ERROR = 6;

    /**
     * 默认音频文件存放地址BaseSystem.getProjectFolderPath()
     *             + File.separator +
     */
    private static final String DEF_SAVE_PATH = BaseSystem.getProjectFolderPath() + "/audio/";

    private static AudioPlayer mAudioPlayer;

    private MediaPlayer mediaPlayer;

    private OnPlayListener mOnPlayListener;

    private OnSeekCompleteListener mOnSeekCompleteListener;

    private String mp3CacheFolder;

    // private String playUrl;

    private Object tag;

    private boolean isBuffering;

    private boolean isStop;

    private boolean isError;

    private boolean isPasue;

    private PlayPcmThread pcmPlay;

    private String bufferPath;

    private Object bufferTag;

    private boolean bufferPlay;// 缓冲后是否播放

    private boolean autoPlayer;

    /**
     * 播放列表
     */
    private List<String> mMusicList = new ArrayList<String>();

    /**
     * 当前播放歌曲的索引
     */
    private int currentListItme = 0;

    /**
     * 是否连续播放列表
     */
    private boolean isLoopPlay = false;

    /**
     * 播放开始位置
     */
    private int seektoTime = 0;

    /**
     * 播放结束位置
     */
    private int playEndTime = 0;

    private Handler mHandler = new Handler(Looper.getMainLooper());

    /**
     * 获取{@link AudioPlayer}实例 <br />
     * 如果不是在ui线程获取实例，则监听回调需要通过handler来更改ui元素
     * 
     * @return {@link AudioPlayer}
     */
    public static AudioPlayer getInstance()
    {
        if (mAudioPlayer == null)
        {
            synchronized (AudioPlayer.class)
            {
                AudioPlayer inst = mAudioPlayer;
                if (inst == null)
                {
                    inst = new AudioPlayer();
                    mAudioPlayer = inst;
                }
            }
        }
        return mAudioPlayer;
    }

    /**
     * 
     * 播放完毕的回调
     * 
     */
    private void setOnCompletionListener(final Object tag)
    {
        mediaPlayer.setOnCompletionListener(new OnCompletionListener()
        {
            @Override
            public void onCompletion(MediaPlayer mp)
            {
                CWLog.d(TAG, "play finish islooping=" + isLoopPlay
                        + " currentListItme=" + currentListItme + " size="
                        + mMusicList.size());
                if (isLoopPlay)
                {
                    if (currentListItme + 1 == mMusicList.size())
                    {
                        isLoopPlay = false;
                        currentListItme = 0;
                        seektoTime = 0;
                        playEndTime = 0;
                        mMusicList.clear();
                        if (mOnPlayListener != null)
                        {
                            mOnPlayListener.stop(tag);
                        }

                    }
                    else
                    {
                        nextMusic();
                    }
                }
                else
                {
                    if (mOnPlayListener != null)
                    {
                        mOnPlayListener.stop(tag);
                    }
                }
            }
        });
    }

    /**
     * 
     * 构造函数<br />
     * 如果不是在ui线程创建，则监听回调需要通过handler来更改ui元素
     * 
     * @param cacheFolder
     *            缓存目录
     */
    private AudioPlayer()
    {
        mp3CacheFolder = getDefAudioSavePath();
        autoPlayer = true;
        mediaPlayer = new MediaPlayer();
        // setOnCompletionListener();
    }

    private void playListener()
    {
        if (mediaPlayer != null && mediaPlayer.isPlaying())
        {
            if (mOnPlayListener != null)
            {
                if (playEndTime > 0)
                {
                    if (playEndTime <= mediaPlayer.getCurrentPosition())
                    {
                        stop();
                    }
                    else
                    {
                        mOnPlayListener.onPlaying(mediaPlayer.getDuration(),
                                mediaPlayer.getCurrentPosition());
                    }
                }
                else
                {
                    mOnPlayListener.onPlaying(mediaPlayer.getDuration(),
                            mediaPlayer.getCurrentPosition());
                }
            }
            mHandler.postDelayed(new Runnable()
            {

                @Override
                public void run()
                {
                    playListener();
                }
            }, 100);
        }
        else if (mOnPlayListener != null)
        {
            if (!isPasue)
            {
                mOnPlayListener.onPlaying(mediaPlayer.getDuration(),
                        mediaPlayer.getDuration());
            }
        }
    }

    /**
     * 获取默认音频存放目录,如果创建不成功则返回null
     * 
     * @return 默认音频存放目录
     */
    private String getDefAudioSavePath()
    {
        File f = getDefAudioSaveFolder();
        return f == null ? null : f.getAbsolutePath();
    }

    /**
     * 获取默认音频存放目录,如果创建不成功则返回null
     * 
     * @return 默认音频存放目录
     */
    private File getDefAudioSaveFolder()
    {
        File f = new File(DEF_SAVE_PATH);
        if (!f.exists())
        {
            if (!f.mkdirs())
            {
                f = null;
            }
        }
        return f;
    }

    /**
     * 设置播放监听事件</br><b
     * style="color:red">必须在play()前调用,否则可能不会调用mOnPlayListener.onPlayStart()</b>
     * 
     * @param listener
     *            {@link OnPlayListener}
     */
    public AudioPlayer setOnPlayListener(OnPlayListener listener)
    {
        mOnPlayListener = listener;
        return this;
    }

    /**
     * 设置拉动播放监听事件</br><b 必须在play()前调用
     * 
     * @param listener
     *            {@link OnSeekCompleteListener}
     */
    public AudioPlayer setOnSeekCompleteListener(OnSeekCompleteListener listener)
    {
        mediaPlayer.setOnSeekCompleteListener(listener);
        return this;
    }

    /**
     * 设置拉动播放监听事件</br><b 必须在play()前调用
     * 
     * @param msec
     *            单位 毫秒
     */
    public AudioPlayer seekTo(int msec)
    {
        if (mediaPlayer != null && mediaPlayer.isPlaying())
        {
            mediaPlayer.seekTo(msec);
            mediaPlayer.start();
        }
        else
        {
            seektoTime = msec;
        }
        return this;
    }

    /**
     * 是否在播放
     * 
     * @return 是否在播放
     */
    public boolean isPlaying()
    {
        CWLog.i(TAG, "----------isPlaying");
        if (isStop)
        {
            return false;
        }
        return mediaPlayer != null && mediaPlayer.isPlaying();
    }

    /**
     * 是否在缓冲
     * 
     * @return 是否在缓冲
     */
    public boolean isBuffering()
    {
        return mediaPlayer == null ? false : isBuffering;
    }

    /**
     * 停止播放
     * 
     */
    public AudioPlayer stop()
    {
        isLoopPlay = false;
        currentListItme = 0;
        mMusicList.clear();
        isStop = true;
        isBuffering = false;
        seektoTime = 0;
        playEndTime = 0;
        CWLog.i(TAG, "-----------stop");
        if (mediaPlayer != null && mediaPlayer.isPlaying())
        {
            mediaPlayer.stop();
            if (mOnPlayListener != null)
            {
                mOnPlayListener.stop(tag);
            }
        }
        else if (pcmPlay != null)
        {
            pcmPlay.stopPlay();
        }
        return this;
    }

    /**
     * 释放资源
     * 
     */
    public AudioPlayer release()
    {
        CWLog.i(TAG, "-----------release");
        if (mediaPlayer != null)
        {
            mHandler.removeCallbacksAndMessages(null);
            mediaPlayer.stop();
            mediaPlayer.reset();
            mediaPlayer.release();
            mAudioPlayer = null;
        }
        return this;
    }

    private AudioPlayer playLocal(String local, Object tag)
    {
        if (mediaPlayer != null)
        {
            if (mediaPlayer.isPlaying())
            {
                mediaPlayer.stop();
            }
            if (pcmPlay != null)
            {
                pcmPlay.stopPlay();
            }
            setOnCompletionListener(tag);
            this.tag = tag;
            mediaPlayer.reset();
            try
            {
                CWLog.d(TAG, "local:" + local);
                File file = new File(local.substring(8));
                FileInputStream fis = new FileInputStream(file);
                mediaPlayer.setDataSource(fis.getFD());
                mediaPlayer.prepare();
                if (seektoTime > 0)
                {
                    mediaPlayer.seekTo(seektoTime);
                }
                if (autoPlayer)
                {
                    mediaPlayer.start();
                    playListener();
                }
                else
                {
                    autoPlayer = true;
                }
                seektoTime = 0;
                bufferPlay = true;
                if (mOnPlayListener != null)
                {
                    mOnPlayListener
                            .onReadPlayer(mediaPlayer.getDuration(), tag);
                }
            }
            catch (IOException e)
            {
                e.printStackTrace();
                if (mOnPlayListener != null)
                {
                    mOnPlayListener.onError(PLAY_ERROR_INIT, tag);
                }
            }
        }
        return this;
    }

    private void startPlay(final Object tag)
    {
        if (mOnPlayListener != null)
        {
            mOnPlayListener.onPlayStart(tag);
        }
    }

    private AudioPlayer playHttp(final String url, final Object tag)
    {
        String file = StringUtils.md5(url);
        final File temp = new File(mp3CacheFolder, StringUtils.md5(file
                + "_complete"));
        if (temp.exists())
        {
            startPlay(tag);
            playLocal("file://" + temp.getAbsolutePath(), tag);
        }
        else
        {
            String savePath = new File(mp3CacheFolder, file).getAbsolutePath();
            AsyncDownload download = AsyncDownload.getInstance();
            isBuffering = true;
            CWLog.i(TAG, "isBuffering");
            download.addTask(url, null, savePath,
                    new AsyncDownload.OnProgressUpdate()
                    {
                        @Override
                        public void progressUpdate(long total, long progress,
                                Object tag)
                        {
                            if (!isStop)
                            {
                                if (mOnPlayListener != null)
                                {
                                    mOnPlayListener.onBuffer(url, progress,
                                            total);
                                }
                            }
                            else
                            {
                                autoPlayer = true;
                            }
                        }

                        @Override
                        public void error(int errorType, DownloadTask task)
                        {
                            String file = task.getTag().toString();
                            FileUtils.delete(file);
                            isBuffering = false;
                            autoPlayer = true;
                            CWLog.i(TAG, "isStop:" + isStop + "    isPasue:"
                                    + isPasue);
                            if (!isStop && !isPasue)
                            {
                                if (mOnPlayListener != null)
                                {
                                    mOnPlayListener.onError(
                                            PLAY_ERROR_DOWNLOAD, tag);
                                }
                            }
                            CWLog.d(TAG, "------error:" + file
                                    + "     errorType:" + errorType);
                        }

                        @Override
                        public void complete(DownloadTask task)
                        {
                            isBuffering = false;
                            String file = task.getTag().toString();
                            File src = new File(file);
                            src.renameTo(temp);
                            CWLog.i(TAG, "url:" + temp.getAbsolutePath());
                            bufferPath = "file://" + temp.getAbsolutePath();
                            bufferTag = url;
                            if (!isStop && !isPasue)
                            {
                                playLocal(bufferPath, url);
                                startPlay(url);
                            }
                            else
                            {
                                autoPlayer = true;
                            }
                        }

                        @Override
                        public void completed(DownloadTask task)
                        {
                            isBuffering = false;
                            String file = task.getTag().toString();
                            File src = new File(file);
                            src.renameTo(temp);
                            bufferPath = "file://" + temp.getAbsolutePath();
                            bufferTag = url;
                            if (!isStop && !isPasue)
                            {
                                playLocal(bufferPath, url);
                                CWLog.d(TAG, "------completed:" + file);
                                startPlay(url);
                            }
                            else
                            {
                                autoPlayer = true;
                            }
                        }
                    }, savePath, AsyncDownload.PRIORITY_HIGHT);
        }
        return this;
    }

    /**
     * 播放本地的pcm数据，目前只支持本地
     * 
     * @param pcmPath
     *            数据源
     * @param callbackTag
     *            回调标识
     * @return {@link AudioPlayer}
     */
    public AudioPlayer playPcm(String pcmPath, Object callbackTag)
    {
        if (pcmPlay != null)
        {
            pcmPlay.stopPlay();
        }
        pcmPlay = new PlayPcmThread(pcmPath, callbackTag);
        pcmPlay.setOnPlayerListener(mOnPlayListener);
        pcmPlay.start();
        return this;
    }

    /**
     * 播放raw音频资源
     * 
     * @param rawResId
     *            raw音频资源
     * @param context
     *            上下文
     * @param callbackTag
     *            标识
     * @return {@link AudioPlayer}
     */
    public AudioPlayer play(int rawResId, Context context, Object callbackTag)
    {
        isStop = false;
        if (rawResId == 0)
        {
            if (mOnPlayListener != null)
            {
                mOnPlayListener.onError(PLAY_ERROR_MP3, callbackTag);
            }
        }
        if (mediaPlayer != null)
        {
            if (mediaPlayer.isPlaying())
            {
                mediaPlayer.stop();
            }
            else if (pcmPlay != null)
            {
                pcmPlay.stopPlay();
            }
            mediaPlayer.reset();
            mediaPlayer = MediaPlayer.create(context, rawResId);
            setOnCompletionListener(callbackTag);
            this.tag = callbackTag;
            // mediaPlayer.prepare();
            mediaPlayer.start();
        }
        return this;
    }

    /**
     * 播放音频流
     * 
     * @param mp3FileDesc
     *            音频{@link FileDescriptor}
     * @param callbackTag
     *            回传参数
     * @return {@link AudioPlayer}
     */
    public AudioPlayer play(FileDescriptor mp3FileDesc, String callbackTag)
    {
        isStop = false;
        if (mp3FileDesc == null)
        {
            if (mOnPlayListener != null)
            {
                mOnPlayListener.onError(PLAY_ERROR_MP3, callbackTag);
            }
        }
        if (mediaPlayer != null)
        {
            if (mediaPlayer.isPlaying())
            {
                mediaPlayer.stop();
            }
            setOnCompletionListener(callbackTag);
            this.tag = callbackTag;
            mediaPlayer.reset();
            try
            {
                mediaPlayer.setDataSource(mp3FileDesc);
                mediaPlayer.prepare();
                mediaPlayer.start();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        return this;
    }

    /**
     * 播放
     * 
     * @param mp3
     *            播放地址，支持http://，file://
     * @return {@link AudioPlayer}
     */
    public AudioPlayer play(String mp3)
    {
        play(mp3, mp3);
        return this;
    }

    /**
     * 播放
     * 
     * @param mp3
     *            播放地址，支持http://，file://
     * @return {@link AudioPlayer}
     */
    public AudioPlayer play(String mp3, boolean autoPlayer)
    {
        this.autoPlayer = autoPlayer;
        play(mp3, mp3);
        return this;
    }

    /**
     * 播放
     * 
     * @param mp3
     *            播放地址，支持http://，file://
     * @return {@link AudioPlayer}
     */
    public AudioPlayer play(String mp3, boolean autoPlayer, int seektoTime,
            int playEndTime)
    {
        this.autoPlayer = autoPlayer;
        this.seektoTime = seektoTime;
        this.playEndTime = playEndTime;
        play(mp3, mp3);
        return this;
    }

    /**
     * 播放
     * 
     * @param mp3
     *            播放地址，支持http://，file://
     * @param tag
     *            标识
     * @return {@link AudioPlayer}
     */
    public AudioPlayer play(String mp3, Object tag)
    {
        CWLog.d(TAG, "mp3=" + mp3);
        isStop = false;
        isError = false;
        isPasue = false;
        bufferPlay = false;
        if (mp3 == null || "".equals(mp3))
        {
            if (mOnPlayListener != null)
            {
                mOnPlayListener.onError(PLAY_ERROR_MP3, mp3);
            }
        }
        this.tag = tag;
        if (mp3.startsWith("http://"))
        {
            playHttp(mp3, tag);
        }
        else if (mp3.startsWith("file://"))
        {
            startPlay(tag);
            playLocal(mp3, tag);
        }
        else
        {
            if (mOnPlayListener != null)
            {
                mOnPlayListener.onError(PLAY_ERROR_NOT_SUPORT_SCHEMA, mp3);
            }
        }
        return this;
    }

    /**
     * 
     * 连续播放
     * 
     * @param urls
     * @return
     */
    public AudioPlayer play(String[] urls)
    {
        if (urls == null || urls.length == 0)
            if (mOnPlayListener != null)
            {
                mOnPlayListener.onError(PLAY_ERROR_MP3, urls);
            }
        int length = urls.length;
        mMusicList.clear();
        currentListItme = 0;
        AsyncDownload download = AsyncDownload.getInstance();
        for (int i = 0; i < length; i++)
        {
            mMusicList.add(urls[i]);
            downloadMusic(urls[i], download);
        }
        isLoopPlay = true;
        String url = urls[currentListItme];
        play(url, url);
        return this;
    }

    /**
     * 
     * 下载音频文件
     * 
     * @param url
     *            下载地址
     * @param download
     *            下载任务
     */
    private void downloadMusic(final String url, AsyncDownload download)
    {
        String file = StringUtils.md5(url);
        final File temp = new File(mp3CacheFolder, StringUtils.md5(file
                + "_complete"));
        if (!temp.exists())
        {
            String savePath = new File(mp3CacheFolder, file).getAbsolutePath();

            isBuffering = true;
            CWLog.i(TAG, "isBuffering");
            download.addTask(url, null, savePath,
            /*
             * new AsyncDownload.OnProgressUpdate() {
             * 
             * @Override public void progressUpdate(long total, long progress,
             * Object tag) { if (!isStop) { if (mOnPlayListener != null) {
             * mOnPlayListener.onBuffer(url, progress, total); } } else {
             * autoPlayer = true; } }
             * 
             * @Override public void error(int errorType, DownloadTask task) {
             * String file = task.getTag().toString(); FileUtils.delete(file);
             * isBuffering = false; autoPlayer = true; CWLog.i(TAG, "isStop:" +
             * isStop + "    isPasue:" + isPasue); if (!isStop && !isPasue) { if
             * (mOnPlayListener != null) { mOnPlayListener.onError(
             * PLAY_ERROR_DOWNLOAD, tag); } } CWLog.d(TAG, "------error:" + file
             * + "     errorType:" + errorType); }
             * 
             * @Override public void complete(DownloadTask task) { isBuffering =
             * false; String file = task.getTag().toString(); File src = new
             * File(file); src.renameTo(temp); CWLog.i(TAG, "url:" +
             * temp.getAbsolutePath()); bufferPath = "file://" +
             * temp.getAbsolutePath(); bufferTag = url; if (!isStop && !isPasue)
             * { playLocal(bufferPath, url); startPlay(url); } else { autoPlayer
             * = true; } }
             * 
             * @Override public void completed(DownloadTask task) { isBuffering
             * = false; String file = task.getTag().toString(); File src = new
             * File(file); src.renameTo(temp); bufferPath = "file://" +
             * temp.getAbsolutePath(); bufferTag = url; if (!isStop && !isPasue)
             * { playLocal(bufferPath, url); CWLog.d(TAG, "------completed:" +
             * file); startPlay(url); } else { autoPlayer = true; } } }
             */null, savePath, AsyncDownload.PRIORITY_HIGHT);
        }

    }

    /**
     * 
     * 播放下一首
     * 
     */
    private void nextMusic()
    {
        if (mMusicList == null || mMusicList.isEmpty()
                || ++currentListItme >= mMusicList.size())
            return;
        String url = mMusicList.get(currentListItme);
        play(url, url);

    }

    /**
     * 暂停后继续播放
     * 
     */
    public void resume()
    {
        if (mediaPlayer != null && !mediaPlayer.isPlaying() && !isBuffering)
        {
            if (seektoTime > 0)
            {
                mediaPlayer.seekTo(seektoTime);
            }
            mediaPlayer.start();
            seektoTime = 0;
            playListener();
        }
        else if (!bufferPlay && !isBuffering)
        {
            playLocal(bufferPath, bufferTag);
        }
        if (pcmPlay != null)
        {
            pcmPlay.resumePlay();
        }
        isPasue = false;
    }

    /**
     * 暂停播放
     * 
     */
    public void pause()
    {
        if (mediaPlayer != null && mediaPlayer.isPlaying() && !isBuffering)
        {
            mediaPlayer.pause();
        }
        else if (pcmPlay != null)
        {
            pcmPlay.pausePlay();
        }
        seektoTime = 0;
        playEndTime = 0;
        isPasue = true;
    }

    /**
     * 是否是在暂停状态
     * 
     * @return 在暂停状态
     */
    public boolean isPause()
    {
        return isPasue;
    }

    /**
     * 是否播放出错
     * 
     * @return 播放出错
     */
    public boolean isError()
    {
        return isError;
    }

    public Object getCurrentPlayMp3()
    {
        return tag;
    }

    /**
     * 
     * Gets the current playback position.
     * 
     * @return the current position in milliseconds
     */
    public long getCurrentPosition()
    {
        return mediaPlayer == null ? 0 : mediaPlayer.getCurrentPosition();
    }

    /**
     * Gets the duration of the file.
     * 
     * @return the duration in milliseconds
     */
    public long getDuration()
    {
        return mediaPlayer == null ? 0 : mediaPlayer.getDuration();
    }

    public MediaPlayer getMediaPlayer()
    {
        return mediaPlayer;
    }
}
